/*
 * Copyright (c) Jiandong.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */


import hilog from '@ohos.hilog';
import Context from '@ohos.application.context';

import { ReactContext } from './ReactContext';
import { JSBundleLoaderDelegate } from './JSBundleLoaderDelegate';

export abstract class JSBundleLoader {

  private static readonly Tag = "React JSBundleLoader"

  public static createResourceLoader(
    context: Context.AbilityContext, resourceUrl: string, loadSynchronously: boolean): JSBundleLoader {// assets://index.android.bundle

    hilog.info(0x0000, JSBundleLoader.Tag, `createResourceLoader, resourceUrl: ${resourceUrl}`)

    return ((context: Context.AbilityContext, resourceUrl: string, loadSynchronously: boolean) => {
      return new class AssetJSBundleLoader extends JSBundleLoader {
        constructor(private context: Context.AbilityContext, private resourceUrl: string, private loadSynchronously: boolean) {
          super()
        }

        public loadScript(delegate: JSBundleLoaderDelegate): string {
          delegate.loadScriptFromResource(context.resourceManager, resourceUrl, loadSynchronously);
          return resourceUrl;
        }
      }

      (context, resourceUrl, loadSynchronously)
    })(context, resourceUrl, loadSynchronously)
  }

  public static createFileLoader(fileName: string, resourceUrl: string = fileName, loadSynchronously: boolean = false): JSBundleLoader {
    hilog.info(0x0000, JSBundleLoader.Tag, `createFileLoader, fileName: ${fileName}, resourceUrl: ${resourceUrl}, loadSynchronously: ${loadSynchronously}}`)

    return ((fileName: string, resourceUrl: string, loadSynchronously: boolean) => {
      return new class FileJSBundleLoader extends JSBundleLoader {
        constructor(private fileName: string, private resourceUrl: string, private loadSynchronously: boolean) {
          super()
        }

        public loadScript(delegate: JSBundleLoaderDelegate): string {
          delegate.loadScriptFromFile(this.fileName, this.resourceUrl, loadSynchronously);
          return fileName;
        }
      }

      (fileName, resourceUrl, loadSynchronously)
    })(fileName, resourceUrl, loadSynchronously)
  }

  public static createDirectRunLoader(fileName?: string, resourceUrl?: string, loadSynchronously?: boolean): JSBundleLoader {
    hilog.info(0x0000, JSBundleLoader.Tag, `createDirectRunLoader, fileName: ${fileName}, resourceUrl: ${resourceUrl}.`)

    return (() => {
      return new class FileJSBundleLoader extends JSBundleLoader {
        public loadScript(delegate: JSBundleLoaderDelegate): string {
          delegate.directRunScript();
          return fileName;
        }
      }
    })()
  }

  public static createCachedBundleFromNetworkLoader(sourceURL: string, cachedFileLocation: string): JSBundleLoader {
    hilog.info(0x0000, JSBundleLoader.Tag, `createCachedBundleFromNetworkLoader, sourceURL: ${sourceURL}, cachedFileLocation: ${cachedFileLocation}`)

    return ((sourceURL: string, cachedFileLocation: string) => {
      return new class CachedBundleFromNetworkJSBundleLoader extends JSBundleLoader {
        constructor(private sourceURL: string, private cachedFileLocation: string) {
          super()
        }

        public loadScript(delegate: JSBundleLoaderDelegate): string {
          try {
            delegate.loadScriptFromFile(this.cachedFileLocation, this.sourceURL, false);
            return this.sourceURL;
          } catch (e: any) {
            throw Error(sourceURL + (e as Error).message);
          }
        }
      }

      (sourceURL, cachedFileLocation)
    })(sourceURL, cachedFileLocation)
  }

  public static createRemoteDebuggerBundleLoader(proxySourceURL: string, realSourceURL: string): JSBundleLoader {
    hilog.info(0x0000, JSBundleLoader.Tag, `ccreateRemoteDebuggerBundleLoader, proxySourceURL: ${proxySourceURL}, realSourceURL: ${realSourceURL}.`)

    return ((proxySourceURL: string, realSourceURL: string) => {
      return new class CachedBundleFromNetworkJSBundleLoader extends JSBundleLoader {
        constructor(private proxySourceURL: string, private realSourceURL: string) {
          super()
        }

        public loadScript(delegate: JSBundleLoaderDelegate): string {
          delegate.setSourceURLs(realSourceURL, proxySourceURL);
          return this.realSourceURL
        }
      }

      (proxySourceURL, realSourceURL)
    })(proxySourceURL, realSourceURL)
  }

  public abstract loadScript(delegate: JSBundleLoaderDelegate): string;
}
